home *** CD-ROM | disk | FTP | other *** search
/ Monster Media 1996 #15 / Monster Media Number 15 (Monster Media)(July 1996).ISO / prog_c / lsdoor09.zip / LSDOOR.DOC < prev    next >
Text File  |  1996-06-03  |  64KB  |  1,251 lines

  1.                        LsDoor Software  Development Kit
  2.                             Version 0.9 Wide Beta
  3.                             
  4.                                  June   1996
  5.  
  6.   Thank you for trying out the LsDoor Software Development Kit.  We hope you
  7. find it to be as useful and as powerful as we have.  
  8.   This is the first public release of the LightSpeed SDK.  We will work to
  9. provide rapid improvements as soon as they are needed.  In the next few
  10. versions, we plan some slightly improved documentation, speed improvements,
  11. bug-fixes as they become necessary, as well as anything else which you
  12. request.
  13.  
  14.   A note about our technical support:  We will try to provide help for
  15. anyone who uses this product, be it a registered user or not.  Unfortunetely,
  16. we have limited resources for technical support.  See the end of this
  17. document for details.
  18.  
  19.   About registeration:  See the enclosed file REGISTER.FRM for this
  20. information, and for details about the shareware vs registered LsDoor SDK.
  21.  
  22.   LEGAL NOTE:
  23.  
  24.   By using or attempting to use this product in any way, you signify your
  25. acceptance and clear understanding of all terms and conditions stated in
  26. LICENSE.DOC.  If LICENSE.DOC is missing from this document, then your copy
  27. of this product is illegal and should be destroyed.
  28.  
  29.   WIDE BETA NOTICE:
  30.  
  31.   This is a wide beta version of the LsDoor SDK.  This means that it is an
  32. early version and may have bugs.  Because it is a WIDE beta, it is open to
  33. the general public.  Anyone who uses this does so at their own risk.  Please
  34. report any bugs to us in a thorough and complete manor, and we will fix
  35. them promptly.  Also see LICENSE.DOC.
  36.  
  37.   Introduction....
  38.     
  39.     The LsDoor SDK is a toolkit which programmers can use to create
  40.   their own door programs.  The idea of the kit is to allow door programmers
  41.   to write programs which will support all BBS Software at once.  It will
  42.   also allow programmers to use the native computer language of "C" and "C++"
  43.   without the need to learn a completely new properiety language.  Many
  44.   properiety languages created for BBS Programmers give the programmer no
  45.   real advantange over a more standard language.
  46.     The C/C++ language is the most common computer language in use today.  It
  47.   has been for many years.  We would like to offer Pascal support (the second
  48.   most popular language) however we have no programmers experienced in
  49.   Pascal to port our source code over.
  50.     The LsDoor SDK is a library (.Lib file) which links with your own source
  51.   code to allow you to create virtually any on-line gaming experience you
  52.   can dream up.  The kit is very simple to use, and yet extremely powerful.
  53.   The reason for this is two-fold:  First, we took the LsDoor SDK directly
  54.   from our BBS Software's source code.  When we created the BBS Software
  55.   (titled LightSpeed), we planned the LsDoor SDK right from the start.  We
  56.   used a simple mechanism to tag what code would be included and what
  57.   wouldn't.  The second reason is that we have, to-date, created 6 doors with
  58.   the kit.  These doors were then included with the registered LightSpeed
  59.   free of charge, giving LightSpeed more out-of-the-box features than any
  60.   other BBS Software.
  61.     The result is the most powerful library available for door programming.
  62.   It is capable of almost everything your doors will need.  We've even set
  63.   it up so that registered LightSpeed sysops can use the SDK free of charge
  64.   with their LightSpeed BBS Software, another out-of-the-box feature
  65.   allowing any sysop who also knows C/C++ programming to do some serious
  66.   customization on their BBS, or just create the wackiest door anyone has
  67.   ever seen.
  68.  
  69.     Please note that we also refer to the LsDoor Software-Development-Kit
  70.   as the "SDK", the "door kit", and just the "kit" throughout this document.
  71.  
  72.   Platforms:
  73.  
  74.    *  Any LightSpeed BBS (InfoLink.Dat drop-file) is supported in the
  75.      shareware SDK.
  76.    *  Any standard BBS (Door.Sys drop-file) is supported in the registered
  77.      SDK.
  78.    *  Legend Of the Red Dragon (LORD) IGM support is provided, however you
  79.      may not sell your IGM programs without registering.
  80.    *  Runs on any 80386+ processor, includes support for DesqView,
  81.      DesqView/X, Windows 3.1+, Windows 95, TopView, and a number of other
  82.      operating systems.
  83.    *  Will support the upcoming LTerm standard (we will offer an upgrade to
  84.      the SDK for this support.)
  85.  
  86.   Features:
  87.  
  88.    *  Easy to program, and very powerful!  Your door can be started with as
  89.      little as 3 lines of code!  That doesn't comprimise its power though,
  90.      because there are hundreds of functions available for everything you
  91.      need!  You can worry about your door instead of why the modem keeps
  92.      hanging up.
  93.  
  94.    *  Built-in B-Tree Indexing module, and complete database system!  Setup
  95.      a complete player database for your RPG Game without ever openning a
  96.      file, and yet have data access at frightning speeds!  Just ponder the
  97.      problem of a user first connecting to a BBS.  If a BBS has thousands of
  98.      members, how long will it can take a while to find one person's account
  99.      (which tends to be around 300 bytes) out of all those thousands?  With
  100.      the LsDoor SDK, not even a second in most cases.  It even has a cache!
  101.  
  102.    *  Built-in messaging system.  Includes an easy to use full-screen message
  103.      editor (with ANSI) or an alternate line-editor for non-color (Ascii)
  104.      users.  Supports up to 150 lines with lots of function keys.  You can
  105.      use the message buffer however you like (for example, the lsFaq
  106.      companion to LightSpeed uses the message editor with a maximum
  107.      of 15 lines, but instead of "sending" the message to another user, it
  108.      writes the message to a text file.)
  109.  
  110.    *  With help from the LsText companion to LightSpeed, you can setup
  111.      customizable text for your door.  This way sysops can change the
  112.      strings however they like (you can select which strings can be
  113.      modified.)  This can be a little cryptic to use as yet because the
  114.      strings are referenced by integers.  But to the sysop it works great.
  115.      You'll have two files, a .BIN and .DAT.  The .BIN will always include
  116.      your original text and can't be changed.  The .DAT can be modified by
  117.      the sysop.  As the sysop is using the LsText editor, each prompt
  118.      is displayed in the .BIN and .DAT form simultaniously.  This saves
  119.      memory, but costs some speed and disk space.  This is, of course,
  120.      optional.
  121.  
  122.    *  Time management, user credits, inactivity detect, InfoLink.Dat,
  123.      Door.Sys (+See below), and carrier detect work flawlessly.  When a
  124.      door is running from a LightSpeed BBS, it barely seems to be a door at
  125.      all.
  126.  
  127.    *  A complete status line is available.  The F1 and F2 keys function
  128.      identical to LightSpeed, that is, they shrink or enlardge the status
  129.      line.
  130.  
  131.    *  Sysop chat is nothing less than superb.  For ansi+ users, a very nice
  132.      split screen chat system.  For ascii users, a simpler free-type mode is
  133.      provided (you can't do a whole lot with Ascii.)  Activated by F10.
  134.      Except in some Door.Sys apps, a user's time doesn't change during a
  135.      sysop chat (they won't loose time because the sysop interrupted them.)
  136.  
  137.    *  Time adjustment features (Note that these may not always work with
  138.      Door.Sys) built in to the F7 and F8 keys.  Press them for +/- 5
  139.      minutes, hold down Ctrl or Alt for +/- 15 and +/- 1 minute adjustments.
  140.      Hey, we're thorough about it!
  141.  
  142.    *  Security is always on guard.  The user's 'doorlevel' setting is always
  143.      available, unfortunetely it's just a number that the sysop can assign
  144.      each security class.  When running under LightSpeed, access to all
  145.      security class information is provided.
  146.  
  147.    *  Integrated!  When operating with a LightSpeed Host, your door can
  148.      access much of the same data LightSpeed uses.  Mail, user accounts,
  149.      and even the BBS configuration are available and can be modified.  This
  150.      is the outer limits of customization features.  Note that it IS possible
  151.      to detect and adapt to LightSpeed Host, meaning that you can make use
  152.      of the extra LightSpeed-only features when the sysop is using
  153.      LightSpeed, or switch to Door.Sys-only features when the sysop is using
  154.      another BBS Software.
  155.  
  156.    *  Reliable.  While the problem doesn't apply to the LsDoor SDK, the only
  157.      part of LightSpeed we're at all disappointed in is the message system.
  158.      But, that's good reason to fix it, and we intend to do so in the
  159.      following months.  Messages should work fine within your door, as
  160.      long as the quantity doesn't get to be as enormous as a main BBS message
  161.      base is faced with (i.e. thousands of messages going around at one
  162.      time.)
  163.  
  164.    *  Automatically detects and supports DesqView, DesqView/X, Windows 3.x,
  165.      Windows 95, and any other multi-tasking software which offers the
  166.      time-release interrupts.  For speed and flexibility, upon detecting
  167.      DesqView support, the kit will find the DesqView screen buffer instead
  168.      of writting directly to the video display.  This enables very fast
  169.      operation under DesqView without sacrificing any performance.  Note
  170.      that no support for local graphics is provided, however you could
  171.      write some.  See next item.
  172.  
  173.    *  Supports Ascii (Non-Color), Ansi (Text Color Standard), and remote RIP
  174.      operation.  RIP codes will show up as garbage on the local display,
  175.      however it should show up just fine to the user.  You can adjust your
  176.      door's behavior based on the terminal type.
  177.  
  178.    *  Built-in ANSI Display handler.  We also offer a function almost
  179.      identical to the standard printf() function with additional support for
  180.      color changes on the fly.
  181.  
  182.    *  Support for internal Z-Modem uploads and downloads.  EASY to use.  Get
  183.      a transfer going in 5 lines of code.  Also extendable, add support for
  184.      external protocols, or add more internal protocols.  Z-Modem transfers
  185.      continue to monitor user time, credits, etc. (Except inactivity)
  186.      ** Z-Modem support requires the complete, registered MCOMM Library
  187.         See License.Doc for information.
  188.  
  189.    *  Includes and supports a subset of the MCOMM Serial Library for 
  190.      modem/serial communications.  The DoorKit takes care of all modem
  191.      communications for you (and also allows you limited access to the modem
  192.      for yourself.)
  193.  
  194.   Limitations:
  195.  
  196.    -  [Would like to improve this]  Supports only Borland C/C++ Compiler
  197.      version 3.1 and above.  The door kit is compiled for 386+ Systems,
  198.      but this can be changed on request.  The provided libraries will all
  199.      fail if RUN on anything less than a 386.  
  200.  
  201.    -  No fossil support.  This was removed in favor of internal Z-Modem.
  202.      If we get some requests we can put this back in just a few minutes,
  203.      however there is no way to support Z-Modem through the fossil and 
  204.      the MCOMM Serial Library does an excellent job in place of a fossil (See
  205.      License.Doc.)
  206.  
  207.    -  See REGISTER.FRM for information about the minor limitations of the
  208.      shareware version.
  209.  
  210.   Getting Started...
  211.  
  212.     To setup the LsDoor SDK, just run SETUP.EXE and select your compiler.
  213.     You may need to modify the example project directory settings for your
  214.   particular computer.
  215.  
  216.   Tools:
  217.  
  218.     We've tried to include everything you'll need to develop doors right
  219.   away with the LsDoor SDK.  Everything has been included, except for a
  220.   place to test your product (You CAN just run it in "local" mode.)
  221.     There are a few programs included in the shareware and registered LsDoor
  222.   SDK to make things simpler.  The first is S_IN.EXE.  This is a simple
  223.   program which gives you the return codes for the s_in() function.  See
  224.   the s_in() function below for details.  The next is LSTEXT.EXE, a program
  225.   which is also included in all copies (including shareware) of LightSpeed
  226.   BBS Software, and also may be redistributed with any programs you create
  227.   using the REGISTERED LsDoor SDK.  See Register.Frm for details.
  228.     For a place to test your door, we recommend the LightSpeed BBS Software
  229.   because of its excellent door support.  LightSpeed was carefully designed
  230.   to make door setup and operation a snap.  You are welcome to use any BBS
  231.   Software you choose (if you have the registered LsDoor SDK) or you can do
  232.   without any BBS Software at all, but that isn't advised.  LightSpeed is
  233.   currently available for as low as $ 30.  The shareware edition of
  234.   LightSpeed (and most BBS Software) lacks any door support.
  235.     If you choose to use LightSpeed, you will have an easier time setting up
  236.   and operating door programs.  An example of a typical door's batch file
  237.   for LightSpeed:
  238.  
  239.   C:
  240.   Cd\Doors\MyDoor
  241.   MyDoor.Exe I%InfoLink%
  242.   Exit
  243.  
  244.   Programming the LsDoor SDK:
  245.  
  246.     First let us introduce our style of programming.  We have provided a
  247.   header file called LsDoor.H, which in turn includes all of the other
  248.   header files required to use the SDK.  All the header files except for
  249.   LsDoor.H itself will be hard to read and should generally be avoided (they
  250.   are continually in use by two seperate products, LightSpeed BBS, and the
  251.   LsDoor SDK, and as such, are somewhat messy.  
  252.  
  253.     Note that we use 'uchar' to mean 'unsigned char', 'ushort' to mean
  254.   'unsigned short', 'ulong' for 'unsigned long' etc.  We have macros for
  255.   true and false (all lowercase).  We avoid the Booleon type.  We use a
  256.   'test' type which is an 'unsigned char' meant to only be true/false.
  257.   These types are all typedef'd and declared in the LsDoor.h file (or to be
  258.   exact, in Wiley.h.)
  259.  
  260.     We recommend that programmers start using short and ushort in place of
  261.   int and uint.  The reason for this is because more and more "32-bit" is
  262.   becoming the standard, and in 32-bit programming integers are just that,
  263.   32-bit (the same as long's).  Short's remain unchanged.  So if what you
  264.   really want is a 16-bit variable, use shorts when possible, when you want
  265.   a 32-bit variable, use long's so that your code will still work in the
  266.   old fashioned 16-bit environments.
  267.     Note that the lsDoor SDK uses almost entirely int's.  It will be a major
  268.   task porting it into a protected-mode or 32-bit platform.
  269.  
  270.   Hello World:
  271.  
  272.     The tradition has always been to present a new programming style with a
  273.   "Hello World" program.  Well, let's get traditional:
  274.  
  275.   #define MainModule
  276.   #include "LsDoor.H"
  277.  
  278.   char *errorModule( void ){ return "HelloW"; }     // Show our ID...
  279.  
  280.   void main( void )
  281.   {
  282.     if( !DoorInit( doorsysDISABLE ) ) exit(1);      // Get things rolling.
  283.     display( "\nHello @GGreen world!" );            // Hello Green world!
  284.     display( "\nThe @RRug @BIs @GGreen!" );         // The Rug Is Green!
  285.     exit(0);                                        // Always use exit()
  286.   }
  287.  
  288.   Rule #1:
  289.     All LsDoor programs must provide the function errorModule().
  290.   errorModule() just returns a pointer to the identification of your program.
  291.   If your program experiences any errors, they are always logged A) To the
  292.   user's screen, B) To the local screen, and C) To the Error.Log file.
  293.   The Error.Log file can end up cluttered, as more than one program might
  294.   use it.  By having a short, unique ID included in the Error.Log file, the
  295.   sysop can quickly trace the program that caused the error.
  296.  
  297.   Rule #2:
  298.     One and only one of your program's modules must have the "MainModule"
  299.   macro declared before LsDoor.H is included.  This allows for only one set
  300.   of header files.  When "MainModule" is declared, another #define statement
  301.   inside of LsDoor.h defines the keyword 'global' as nothing.  When
  302.   "MainModule" is not declared, 'global' becomes 'extern'.  You may
  303.   #undef 'global' and/or 'MainModule' after you include the LsDoor.h and
  304.   (optional) Lord.h header.
  305.  
  306.   Rule #3:
  307.     Generally the first thing you want to do is call the DoorInit() function.
  308.   This function gets everything rolling, it reads the dropfiles, it starts
  309.   the clock counting, and it sets up the carrier check.  Put this first
  310.   unless absolutely necessary in your door.  You should always use the if()
  311.   statement shown above (just like that) for calling DoorInit().  DoorInit()
  312.   generally only fails when it has problems with the drop files (i.e. can't
  313.   find them, file error, etc.)  DoorInit() takes one parameter which flags
  314.   whether to allow the Door.sys file or not.  DoorInit() always looks for an
  315.   InfoLink.Dat dropfile first, and if it can't find it, it makes due with a
  316.   Door.Sys drop file, assuming Door.Sys is supported.  The two options for
  317.   the DoorInit() paramater are 'doorsysENABLE' and 'doorsysDISABLE'.
  318.  
  319.   Rule #4:
  320.     Always exit your program using the exit() function.  Otherwise many
  321.   clean-up chores such as closing the serial port (and de-allocating 1K to 4K
  322.   of memory) get left un-done.
  323.  
  324.   The display() routine:
  325.     The display() routine is probably the most frequently used function in
  326.   the kit.  It operates a lot like printf() with some provisions:
  327.  
  328.     %s, %u, %i, etc all work fine.
  329.     Long and Unsigned long integers can't be used.  Use out_long(long/ulong).
  330.     Floating point may or may not work.  Test it before comitting.
  331.     Width and length specifiers (%2.4u) work normally.  Also %*.*u works.
  332.  
  333.     Display also adds the following features (Display finds its meaning
  334.   in life here):
  335.  
  336.     Note that a string which you include via %s can also use all color codes
  337.   and special controls.
  338.  
  339.     Color codes are @X, @x, and @{X} where X is the first letter of a color's
  340.   name.  For example, @G changes the color to bright green.  @B to bright
  341.   blue.  Use uppercase for bright colors and lowercase for dark colors.  The
  342.   @{X} codes use the same letters but ignore case and change the background
  343.   color.
  344.  
  345.     @B   ..Bright Blue                   @b   ..Dark Blue
  346.     @G   ..Bright Green                  @g   ..Dark Green
  347.     @R   ..Bright Red                    @r   ..Dark Red
  348.     @Y   ..Bright Yellow                 @y   ..Dark Yellow (Brown)
  349.     @W   ..Bright White                  @w   ..Dark White
  350.     @M   ..Bright Magenta (Purple)       @m   ..Dark Magenta (Purple)
  351.     @C   ..Bright Cyan                   @c   ..Dark Cyan
  352.     @1   ..Grey                          @0   ..Black
  353.  
  354.     @{0} ..Black Background              @{1} ..Grey background
  355.     @{B} ..Blue Background               @{R} ..Red Background
  356.     @{G} ..Green Background              @{C} ..Cyan Background
  357.     @{Y} ..Yellow (Brown) Background     @{M} ..Magenta (Purple) Background
  358.  
  359.      *  Background colors are not case sensative.  Flash is not supported.
  360.      *  You might want to set your coloring as you first enter the door.  If
  361.         you don't, you are left at the mercy of the BBS's color scheme.
  362.  
  363.     Ex 1)  display( "@rDark @RBright @{R} All Red" );
  364.     Ex 2)  display( "@bBlue @Rs@Wo@Cr@Gt@Ma @0invisible!" );
  365.  
  366.     There are also 2 common ways to re-locate the cursor.  Both methods have
  367.   the same effect, and both will operate on both the local and remote screens
  368.   (you can control this, but that's a later topic.)  Both methods assume the
  369.   upperleftmost coordinate on your screen is 1,1.  Both methods may not
  370.   locate the cursor quite right on the LOCAL screen if a status line is
  371.   blocking the coordinate.  More on that later.  X is always the horizontal
  372.   (across) position and Y is always the vertical (up and down) position.
  373.  
  374.     The first technique is using display() again.  For the display()
  375.   function, use @[XxY] where capital X is the x coordinate and the Y is the
  376.   y coordinate to relocate your cursor to.  The x in the middle is required
  377.   between the two coordinates (it can be either case.)
  378.     Just like color codes, you may use display()'s relocate codes anywhere in
  379.   the string, and any number of them.  The disadvantages of the display()
  380.   technique are the loss of readability, as well as speed loss.  Also, the
  381.   alternative will support a screen of 256x256 whereas display() is limited
  382.   to 99x99.  Normal user screens are 80x25, so that isn't a big problem.
  383.  
  384.     The s_locate(uchar x, uchar y) function simply takes the new position to
  385.   jump to.  It supports up to 256x256 screens.  It is also quite a bit
  386.   faster than display(), and often simpler.
  387.  
  388.     We will cover more of the output functions later, now moving on to input.
  389.  
  390.   Avoiding the crash:
  391.  
  392.     Before you can actually get the input, you have to be aware of the
  393.   dangers of door programming which generally can't be thwarted.  Some
  394.   examples of these are the carrier detect.  Without a carrier detect, a
  395.   user can hang up, and if the BBS happens to be waiting for a response, it
  396.   will wait forever!  One thing that will help this is the inactivity timer,
  397.   which also serves to kindly log users off if they leave their computer
  398.   un-attended (it provides a 1-minute warning, and an explanation of the
  399.   reason for being disconnected.  Under door.sys the inactivity defaults to 5 
  400.   minutes.  Under infolink, the inactivity matches the BBS's configuration.)
  401.     Then of course there's the user's time limit, credits, etc.  It's all
  402.   taken care of.  You will have to make one provision in any "loop" you
  403.   have which has any chance of getting stuck waiting for input.  This
  404.   provision is checking a variable named 'online'.  This variable is true
  405.   as long as the user is connected, and is supposed to remain connected.
  406.   This variable will flip to false as soon as the user disconnects, or the
  407.   user is logged off for any reason.
  408.  
  409.     The 'online' flag is managed by a smart little function which is the
  410.   center of it all:  update().  You generally don't need to worry about this
  411.   function, however make sure it is being called in loops which care about
  412.   the online flag.  If you are using the s_in() function (described in a
  413.   moment) this is automatic.
  414.     Normally when calling update(), update() will simply return most of the
  415.   time, and then perform its work only once every 4 to 20 seconds.  Another
  416.   function is very rarely needed called forced_update() which forces the
  417.   call immidiately.  Overuse of forced_update() will slow things down a
  418.   little bit.
  419.  
  420.   We want your input:
  421.  
  422.     Input is generally a single character.  LightSpeed provides a very useful
  423.   input routine called s_in() which will fetch you one character.  This
  424.   function does it all:
  425.  
  426.     Calls update() automatically.
  427.     Sometimes releases time-slices under multi-taskers (more on that later)
  428.     Formats the character into something useful.
  429.  
  430.     To you, s_in() works a lot like getch().  If the character is a regular
  431.   kind of thing (the letter A or Y for example) then s_in() just returns
  432.   that character.  When the character is an extended code (be it remote or
  433.   local) s_in() returns 0, but unlike getch(), it does not need to be called
  434.   again.  Rather, it puts the second byte (the extended code) into a global
  435.   variable named 'extended'.  This makes things possible such as remote
  436.   users using arrow keys (Caution, if you include support for arrow keys it
  437.   is highly recommend you provide some way for the user to select an
  438.   alternative way of input, we suggest letting them choose between arrow
  439.   keys, the keypad, and some regular keys arranged like the arrow keys.)
  440.     The s_in() function will also translate some special arrow key sequences
  441.   into the normal 0/extended form.
  442.     Clever s_in() also processes what it sees and checks for any special keys
  443.   such as F10 (Sysop Chat) or F1, etc.
  444.     To find out what a s_in() code is, use the included program S_IN.EXE.
  445.   S_in() does not echo the keystroke.
  446.  
  447.     Now with that in mind, let's look at a simple question.  The most common,
  448.   the old Yes or No.
  449.  
  450.   // Example2.Cpp - Asking a question
  451.   #define MainModule
  452.   #include "LsDoor.H"
  453.  
  454.   char *errorModule( void ){ return "Example II"; }  // Identify ourself...
  455.  
  456.   char c;
  457.   void main( void )
  458.   {
  459.     if( !DoorInit( doorsysDISABLE ) ) exit(1);      // Get things started...
  460.     display("\n@WS@wtar @WW@wings @WG@wame" );
  461.     while( online )
  462.     {
  463.       display("\nDo you wish to play?  (Y/N)  ");
  464.       c = toupper( s_in() );          // Toupper is a useful C function
  465.                                       // that converts a 'char' to uppercase.
  466.       if( c == 'Y' )
  467.       {
  468.         display("\nGame over."); exit(0);
  469.       }
  470.       if( c == 'N' )
  471.       {
  472.         display("\nReturning to the 20th century."); break;
  473.       }
  474.     }
  475.     exit(0);                                        // Always use exit()
  476.   }
  477.   // End of Example2.Cpp
  478.  
  479.     The above is a complete program and will run fine.  But, it could use
  480.   some enhancements.  Use the function echo_yn() as a quick way to echo
  481.   a colored YES or NO.  echo_yn() takes a single character, which is either
  482.   'Y', or 'N' (defaults to No).  Then, there's a lot you can do with the
  483.   question "Do you wish to play?".  If you run Example2, the phrase
  484.   Star Wings Game shows up nicely colored.  This is not a requirement, but
  485.   you might want to color your question just a little.  Perhaps figure out
  486.   and make a note of how you want ALL your Y/N's to look.  Seems trivial?
  487.   Might be.  Your program will certainly look more professional if your
  488.   color scheme follows a pattern.  Here's a revision of Example2:
  489.  
  490.   // Examp2B.Cpp - Touched up Example2.Cpp.  Much prettier.
  491.   ...
  492.     while( online )
  493.     {
  494.       display("\n@CD@co you wish to play?  (@GY@w/@gN@c)  ");
  495.       c = toupper( s_in() );               // Convert s_in() to uppercase..
  496.       if( c == 'Y' || c == '\r' )          // Use '\r' for the return key..
  497.       {
  498.         echo_yn('Y'); display("\nGame over."); exit(0);
  499.       }
  500.       if( c == 'N' )
  501.       {
  502.         echo_yn('N'); display("\nReturning to the 20th century."); break;
  503.   ...
  504.   // End of Examp2B.Cpp
  505.  
  506.     Notice that we made the Y in the (Y/N) display bright green, and the
  507.   N dark green?  That seems to work for letting users now that "Y is the
  508.   default.  Just hit enter."  
  509.  
  510.   Local/Remote/Both:
  511.  
  512.     You have seen the s_locate() and s_in() functions.  The display()
  513.   function also follows the s_ function conventions.  There are quite a
  514.   few s_ functions available to you.  All functions preceded by the s_ follow
  515.   some common guidelines:
  516.  
  517.     Automatically take care of calling update()
  518.     React to 'online' flag
  519.     Operate based on the 'redirect' flag
  520.  
  521.     Some other commonly used s_ functions are s_ready(), s_out(), s_gets()
  522.   s_cls(), and s_color().  s_ready() returns true when input is waiting.
  523.   When you call s_in(), your function doesn't return until a key is pressed.
  524.   You can first call s_ready() to find out if it's necessary to call s_in().
  525.   s_cls() simply clears both the remote and local screen.  For Ascii users,
  526.   it just scrolls down 5 lines.  s_out() takes one unsigned char and outputs
  527.   it.
  528.     The s_color() function provides a fast means of changing the color on
  529.   both the local & remote sides (as per the 'redirect' flag.)  The s_color()
  530.   function only changes the color when needed, thus avoiding any unnecissary
  531.   modem clutter.  The s_color() also supports blinking colors unlike the
  532.   display() function.  See also the color table below.
  533.     The s_gets() function is very useful, it gets a character string from the
  534.   user.  s_gets() takes 3 paramaters:  Unsigned char *buffer, int maxlen,
  535.   and char *filter (which defaults to 0.)  'filter' is rarely used.  Buffer
  536.   is a character buffer of at least 'maxlen' bytes which will store the
  537.   input.  Maxlen is the maximum number of bytes that may be input.  For
  538.   example:
  539.     char mystring[15];
  540.     s_gets( mystring, 15 );
  541.  
  542.     All s_ functions respect the 'redirect' flag.  The redirect flag will
  543.   be set to one of these macros:   RE_LOCAL, RE_ECHO, and RE_SERIAL.
  544.   RE_SERIAL disables the local screen, and begins output (or input) from the
  545.   remote user only.  RE_LOCAL disables the remote user and takes input or
  546.   output from the local console only.  RE_ECHO accepts input and
  547.   output from both sources.  You can change the 'redirect' flag as needed,
  548.   but DON'T change the 'drop.redirect' flag.  The 'drop.redirect' flag
  549.   let's you know how you are trully connected.  It uses the same macros
  550.   as redirect.  If you change 'redirect', set it equal to 'drop.redirect'
  551.   when you're done.
  552.     The s_ functions will all operate based on the 'redirect' flag, they
  553.   only pay attention to the 'drop.redirect' flag to avoid writing to a
  554.   modem when in local operations.
  555.    
  556.   Getting the Terminal Settings:
  557.  
  558.     Checking the current user's terminal setting is very easy.  Just check
  559.   the global flag 'terminal'.  The value of 'terminal' should not be
  560.   changed, or if it is it should be restored afterwords.  'terminal' will
  561.   be set to one of these values:
  562.  
  563.     TERM_ASCII          0
  564.     TERM_ANSI           1
  565.     TERM_RIP            2
  566.  
  567.     Don't check if a terminal == TERM_ANSI.  When checking for
  568.   Ansi, and only ansi, always use:  if( terminal >= TERM_ANSI )
  569.  
  570.     The display() routine automatically adjusts to terminal settings.  @X
  571.   codes are ignored for Non-Color Ascii users.
  572.  
  573.   The built-in pager:
  574.  
  575.     The pager is a nice way for users to communicate when teleconference is
  576.   not available.  The pager is built-in to the lsDoor kit, and requires no
  577.   modifications for common support.  You can also extend the pager as a way
  578.   of communication between different nodes (expect from 1-6 seconds for it
  579.   to arrive unless you pad in some forced_update() calls.)  To extend the
  580.   pager in a professional program, you will need your own unique ID number,
  581.   for which you can contact us and receive free of charge.  
  582.     If you need to disable the pager, set the global flag 'read_commlinks'
  583.   to false, and true again to bring it back.  To clear all waiting pages,
  584.   set the global flag 'dump_commlinks' to true.  This will automatically
  585.   be reset to false as soon as update() completes the purge.
  586.  
  587.   Additional routines:
  588.  
  589.     At this point the basics are fairly well covered.  Now we'll hurry things
  590.   up, because we still have a lot to cover.  
  591.  
  592.   Display routines:
  593.  
  594.     void display( char *format, ... );     //  See above...
  595.  
  596.     int s_in();                            //  See above...
  597.  
  598.     short s_out( uchar outch );            //  Outputs outch to 'redirect'
  599.  
  600.     int s_ready( char giveup=true );
  601.         s_ready() will return true only when input is waiting to be
  602.       processed.  If giveup is false, time slices will not be given to any
  603.       detected multi-taskers.  Time-slices are never given if input is ready.
  604.     
  605.     void s_cls();                          //  Clears 'redirect' screen(s)
  606.  
  607.     void s_locate( uchar x, uchar y );
  608.         s_locate(x,y) relocates the cursor for 'redirect' screen(s).
  609.       Coordinates 1,1 are the upperleftmost corner of the screen.  Use up to
  610.       256x256.  This function is faster than display() for relocation.
  611.       * Do NOT call s_locate() unless terminal >= TERM_ANSI
  612.  
  613.     void s_color( ushort color );
  614.         s_color(color) changes the current display color for 'redirect'
  615.       screen(s) if necissary.  This function is faster than display(),
  616.       and supports blinking colors.  The numbering system for s_color() is
  617.       based on hex.  The upper nibble provides the background color and
  618.       the lower provides the foreground color.  Hex 1 is blue, hex F is
  619.       bright white, so 0x1F is bright white on a blue background.  The
  620.       colors are listed in the following table.  To use blinking, add 0x80.
  621.       To use bright foreground colors instead of dark, add 0x8.
  622.       * Do NOT call s_color() unless terminal >= TERM_ANSI
  623.  
  624.       Color Table for s_color() function:  (Numbers are in hex)
  625.         0..  Black              4..  Red
  626.         1..  Blue               5..  Magenta
  627.         2..  Green              6..  Yellow/Brown
  628.         3..  Cyan               7..  White
  629.  
  630.       To use blinking, add 0x80 to your background color.
  631.       To use bright colors, add 0x8 to your foreground color.
  632.       Examples:         0x1F is bright white on blue.
  633.                         0x9F is bright, blinking white on blue
  634.  
  635.     void s_eraseline( void );              //  Erases current display line
  636.         This function works fine with all terminals.  Ansi+ is faster.
  637.  
  638.     void s_backspace( void );              //  Outputs a backspace code
  639.         Always use this function (or send "\b \b") for backspaces.
  640.  
  641.     void echo_yn( char );                  //  Outputs 'Yes' or 'No' (Y or N)
  642.  
  643.     void scanner( void );
  644.     void clear_scanner( void ); 
  645.         Use scanner() during lengthy operations to show a small rotating
  646.       symbol.  For best visual results, call scanner() about every 5
  647.       seconds.  When the operation is done, call clear_scanner() before any
  648.       other output is done.  
  649.  
  650.   General Door Routines:
  651.  
  652.     Also see the miscellanious data section below.
  653.  
  654.     global unsigned long node.ID.num;
  655.         This variable will give the current node number, except the first
  656.       node is always number 0.   
  657.  
  658.     int DoorInit( int allowdoorsys=doorsysENABLE );
  659.         This function initializes your door program.  It will return false in
  660.       the event of an error in which case you should call exit() immidiately.
  661.       After calling this function, you must use the exit() function to exit
  662.       your program in all cases.  Do not use any 'return' statements in your
  663.       main() function.  The paramater 'allowdoorsys' can be either
  664.       doorsysENABLE or doorsysDISABLE.  The shareware LsDoor SDK will always
  665.       use doorsysDISABLE regardless of what value you pass.  DoorInit()
  666.       will always look for a InfoLink.Dat file first and use that if
  667.       possible.
  668.  
  669.     void clear_pause( void );
  670.     int pause( int allowstop=true );
  671.         Pause gives the user a -=Pause=- prompt with options to Continue,
  672.       Stop, or go into Nonstop mode.  This function returns true when the
  673.       user selects Continue or Nonstop and false when the user selects Stop.
  674.       If a user selects Nonstop, pause() will have no effect until you call
  675.       clear_pause().
  676.  
  677.     void activity( void );            // Restarts the inactivity timer 
  678.  
  679.     void forced_update( void );
  680.     void update( void );
  681.         Update should be called in all parts of your program, either by you
  682.       or by the LsDoor functions.  Update() does housekeeping chores such as
  683.       updating timers and inactivity, as well as checking the carrier and
  684.       operating the 'online' flag.  Update() will return without doing
  685.       anything until 4 to 20 seconds (depending on the situation) have passed
  686.       without doing the update.  Forced_update() overrides this 4 to 20
  687.       second limit and calls update() immidiately.
  688.  
  689.     void status_line( void );      // Re-displays and updates the status line
  690.  
  691.     void sysop_chat( void );       // Invokes a sysop chat
  692.  
  693.     uint best_userserch( uchar *find );    // LightSpeed BBS Only
  694.         This function searches through the user database for the handle
  695.       'find'.  It returns true if anything was found and loads the user's
  696.       account into 'userserch'.  Source code for this function can be found
  697.       in Example4.Cpp.
  698.  
  699.     uint best_username( uchar *find );     // LightSpeed BBS Only
  700.         This function searches through the user database and provides the
  701.       best match for the name 'find'.  If a decent match was found, it
  702.       returns true and loads 'userserch' with the person's account.
  703.  
  704.     void hang_up( void );        // Use this to hang up the caller
  705.  
  706.     char *ask_format( const char *text, const char *format, char *s,
  707.                   int newline=false, char required=true );
  708.         This function first displays 'text' and then, following the ## and **
  709.       pattern set by 'format', it retrieves an input string from the user and
  710.       stores it in 's'.  It also returns 's'.  The format can include any
  711.       characters, however only ## and ** give input.  For example, if the
  712.       format is "##/##/##" then the user would have to enter 2 digits, then
  713.       a / would appear, the user enters another 2 digits, another / appears,
  714.       so-on.  The 's' string might be filled with "12/23/85".  A * allows for
  715.       any single character to be input, a # requires a digit only.  The
  716.       'newline' paramater determines if the prompt is displayed on the next
  717.       line or current line.  The 'required' paramater determines if the user
  718.       may press ENTER before completing the input.
  719.  
  720.   Direct Modem Access:
  721.  
  722.     These functions do NO carrier checking, no time checking, and do not
  723.   call update() automatically.  Use them with caution.  Do not use them
  724.   when in local operation.  Some of these functions are macros.
  725.  
  726.     void direct_out( uchar );     // Outputs a character, no processing
  727.  
  728.     void direct_string( char * ); // Outputs the string w/50ms between chars
  729.  
  730.     short direct_ready( void );   // Returns true when modem input is waiting
  731.  
  732.     short direct_in( void );
  733.       This function does not check for keystrokes such as the F-Keys.  If
  734.     you call this function when no input is available, your program could
  735.     crash.  Check if direct_ready() is true before calling.
  736.  
  737.     char carrier( void );        // Returns true when a carrier is present
  738.  
  739.     void set_dtr( int dtr );     // Sets the modem DTR
  740.  
  741.     void set_baud( ulong newbaud );     // Sets the modem baud rate
  742.  
  743.     void disable_port( void );
  744.     void enable_port( void );
  745.         These functions temporarily disable and re-enable a port.  If you
  746.       will be spawning another program, use these to halt the serial port
  747.       while the new program is running.
  748.  
  749.   Pager Routines:
  750.  
  751.     global int read_commlinks, dump_commlinks;
  752.         Set read_commlinks to false to temporarily disable the pager.  Set
  753.       dump_commlinks to true to erase all pending pages (Update() will set it
  754.       back to false when done.)
  755.  
  756.     void save_commlink( int );
  757.         Writes the commlink to disk.  Takes the node number as a paramater,
  758.       using start-at-0 node numbers.  See Example3.Cpp for a demonstration.
  759.  
  760.     uint matches( char *a, char *b );     // Returns # of char's matching..
  761.  
  762.     int FindExactUserOnline( uchar *lookfor );    // Returns node # or -1
  763.  
  764.     int FindUserOnline( uchar *lookfor );
  765.         This function will find the best match for 'lookfor', and also
  766.       assumes that the 'lookfor' string contains additional text after the
  767.       user's handle.  If a user named "King Burgundy" is online, and
  768.       you pass this the string "King Burg Hello" it will return his node
  769.       # and modify the string to show: "Hello".
  770.  
  771.     void PageUser( void );
  772.         This function is a very quick way to implement paging support.  Just
  773.       call this function when the user presses the "page" key, whatever that
  774.       may be.  It will prompt the user for their page and send it off.
  775.  
  776.   Multi-tasker and system clock:
  777.  
  778.     A common fault of many programs is the use of BIOS Interrupt 1Ah,
  779.   function 0x00 to retrieve the system's tick count.  This interrupt was
  780.   apparantely intended only for operating system use.  If this interrupt
  781.   is called after midnight but before the operating system calls the
  782.   interrupt, the system's date can miss a day on some computers.
  783.     
  784.     unsigned long tick_count( void );
  785.         This is a safe way of retrieving the current system tick count.  One
  786.       'tick' occurs 18.2 per second.  The tick count is reset to 0 after
  787.       midnight.
  788.  
  789.     void tick_delay( ulong ticks ); // Delays for 'ticks' giving time slices
  790.  
  791.     int dv_active( void );  // Returns true if desqview is present detected.
  792.  
  793.     void dv_pause( void );  // Gives up time slice to DV, DV/X, Win3.1, Win95
  794.  
  795.   File Transfer:
  796.  
  797.     Use of the LsDoor SDK Z-Modem code requires the fully registered version
  798.   of the MCOMM Library from Mike Dumdei.  See License.Doc for details.  The
  799.   Z-Modem code is useless unless you have the ZMLIB_H.LIB file included in
  800.   your project.  Here's an example of how to build the ZMLIB_H.LIB file to
  801.   work with the LsDoor SDK:
  802.  
  803.     tasm /DTURBOHUGE  /Mx /t /w2 desqv;
  804.     tasm /DTURBOHUGE  /Mx /t /w2 unixdos;
  805.     tasm /DTURBOHUGE  /Mx /t /w2 zfunc;
  806.     bcc -c -X -mh -DNO_ASM batch.c zmdos.c xyzgen.c zcmplr.c
  807.     if exist zmlib_h.lib del zmlib_h.lib
  808.     tlib /C /0 zmlib_h +batch +zmdos +unixdos +desqv +zcmplr +xyzgen
  809.  
  810.   -- The following only applies with the Z-Modem extension (ZMLIB_H.LIB)...
  811.      You must also include ZModem.Cpp from the registered LsDoor SDK in your
  812.      project...
  813.  
  814.     Using File Transfers such as Z-Modem requires a little deviation from
  815.   the usual path.  To use Z-Modem file transfers, you must add a little bit
  816.   of extra code.  While we suggest sticking to Z-Modem, if you are a C++
  817.   Programmer and want to add additional protocals, look over FileXFer.H
  818.   and ZModem.H for more information.  The extra code for Z-Modem will look
  819.   like this: 
  820.  
  821.     ***   Include this code segment to enable Z-Modem File Transfers...
  822.     #include "FileXFer.H"
  823.     #include "ZModem.H"
  824.  
  825.     extern ASYNC Com;
  826.     class DoorZModem : public ZModem {
  827.       public:
  828.         test ResumeTransfer( char *filename ){ return true; }  // * See Below
  829.         DoorZModem( void ) : ZModem( &Com, false )
  830.     } zmodem;
  831.  
  832.     void FileTransferIdle( void ){ resetDoor = 1; update(); dv_pause(); }
  833.     void SentGood( char far *filename );     // + See Below
  834.     ***
  835.      * Note that the above function 'ResumeTransfer()' can return either
  836.     true or false at your descresion.  It will control whether an upload of
  837.     'filename' can be resumed.  For example with a BBS this only returns
  838.     true when the file in question was uploaded by the same person who is
  839.     trying to upload it again.
  840.      + Note that you must provide your own 'SentGood()' function which will
  841.     be called AFTER every successful DOWNLOAD.  For example, LightSpeed's
  842.     SentGood() function charges the user for the download if there are any
  843.     special charges, ratios, etc, associated with that file.
  844.  
  845.     test DisconnectAfterTransfer( void );  // Asks Y/N, returns true or false
  846.   
  847.     void zmodem.Setup( ulong Baud, char *path=0 );
  848.         Call this function before a file transfer.  If you are downloading,
  849.       send only the baud rate the user is connected at (this is for display.)
  850.       If you will be uploading, send the baud rate followed by the directory
  851.       in which to place the file, for example:  "C:\Receive"
  852.  
  853.     void zmodem.Send( char *filename );   // Sends a single file, 'filename'
  854.  
  855.     void zmodem.Add( char *filename );    // Adds 'filename' to the list
  856.     void zmodem.Send( void );             // Sends all files in the list
  857.  
  858.     void zmodem.Rcv( void );     // Receives files from the user
  859.     char *zmodem.GetFileName( void );
  860.         After calling Rcv(), use this function to find out what files
  861.       were received successfully.  GetFileName() will return filenames for
  862.       each of the files received, and then return NULL when there are no
  863.       more files.
  864.  
  865.   Messages:
  866.  
  867.     int maileditor( int lines, char abort, char clearbuf=1 );
  868.         This function edits a message but does not save it to disk.  'lines'
  869.       is the maximum length of the message.  'abort' can be true or false,
  870.       allowing the user to abort the message or forcing them to send it.
  871.       'clearbuf' is normally true, unless you are replying to another
  872.       message.  This function returns true if the user selects to send the
  873.       message, or false if the user chooses to abort.
  874.  
  875.     int show_message( int allowprevious=0 );
  876.         This function displays the message currently loaded in 'buffer' to
  877.       the user.  It can return false when the user selects 'exit', or 1
  878.       when the user selects 'continue', and -1 when the user selects
  879.       'previous' (when enabled.)  
  880.  
  881.   LightSpeed Standard Client/Server Communications
  882.     Revision 1.0 
  883.  
  884.     The Client/Server Communications are a set of functions, tools which you
  885.   can use to build just that, client/server applications.  A client/server
  886.   application is one where a host program works together with a client
  887.   program for a specific purpose.  In this case, the host and client are
  888.   linked via modem, and must be written specifically for each other.
  889.  
  890.     The Client/Server model is used by LightSpeed to allow for a BBS to BBS
  891.   communication.  Any LightSpeed BBS can communicate effectively with another
  892.   BBS using this model.  The Client/Server model is only a small set of
  893.   functions designed to provide the base of a more complex communication
  894.   system.  Unlike the rest of the LightSpeed code, the complete source code
  895.   to the Client/Server standard is provided in the registered LsDoor SDK.
  896.  
  897.     The LsDoor SDK itself makes no use of the Client/Server model.  The
  898.   Clien/Server model is included with the shareware SDK.  The source code
  899.   is also provided in Serial.Cpp for examination only.  All of the
  900.   Client/Server functions use Direct Modem Access, but they provide timeouts
  901.   to prevent crashes.
  902.  
  903.     #define lsTimeout           5    // Value in seconds.
  904.  
  905.     truth timed_in( uchar c );    // Looks for 'c' within 'lsTimeout' seconds
  906.  
  907.     int timed_get( void );  // Waits for input within timeout (Timeout = -1)
  908.  
  909.     truth confirm_in( uchar c );
  910.     int confirm_get( void );
  911.     truth confirm_out( uchar c );
  912.         The confirm_ functions will verify the character, ensuring that the
  913.       character received was the exact character sent and vise-versa.  If
  914.       the receiver will be using confirm_get() or confirm_in() for a
  915.       particular byte, the sender must use confirm_out().  The confirm_in()
  916.       and confirm_out() functions both return true on success and false on
  917.       failure.  The confirm_get() function returns -1 on failure or the
  918.       character received.  
  919.  
  920.     void direct_write( void *dat, uint len );    // Sends raw data
  921.     int direct_read( void *dat, unt len );
  922.         The direct_read() function receives raw data, but only waits for
  923.       'lsTimeout' seconds.  It returns the number of bytes received
  924.       successfully.
  925.  
  926.     int confirm_write( void *dat, uchar len );
  927.     int confirm_read( void *dat, uchar len );
  928.         These two functions work like their direct_ counterparts, except
  929.       with some error-correction techniques.  The confirm_write() function
  930.       sends the length of the string (len) out, then the actual string,
  931.       and then a 32-bit (ulong) checksum.  The confirm_read() function will
  932.       compare the received checksum with its own checksum and send back the
  933.       result (the data was sent ok, or the data is invalid.)  These functions
  934.       will make the attempt 10 times before giving up (except in the case
  935.       of a timeout which will cause them to give up immidiately.)  The
  936.       confirm_write() function waits until the receiver has confirmed the
  937.       reception.  Overall these two functions are extremely slow compared
  938.       to the direct_ functions because they send around 10 extra bytes
  939.       of data and also wait for each other to respond, but that's the cost
  940.       paid for the rather strong insurance that the data is accurate.
  941.  
  942.   LightSpeed TextSystem:
  943.  
  944.     The TextSystem allows you to create 2 data files to include with your
  945.   door program.  You can choose a name for these files, such as MyDoor.*.
  946.   The first file would be MyDoor.Bin, and the second MyDoor.Dat.  These 2
  947.   files hold text strings which your door program can use however it wants.
  948.   Usually, this is used to let the sysop customize the door to say exactly
  949.   what the sysop wants, instead of being forced to use the default prompts.
  950.     These two files are modified using LSTEXT.EXE, a program which you may
  951.   re-distribute with your door if you are using the registered LsDoor SDK
  952.   only.  This program can also be found with any copy of LightSpeed BBS
  953.   Software, included the shareware versions.
  954.     The first file, the .Bin file, holds your default values and cannot be
  955.   changed by the sysop.  The second file, the .Dat file, holds the values
  956.   the sysop wants to use.  For a better idea, go into the LSTEXT Program.
  957.   You can type 'LsText.Exe lsDoorInit' (not case sensative) to create your
  958.   own new data files.  You (or anyone with LSTEXT) can use the "External
  959.   Door" option to modify your data files, which are named BABYTEXT.DAT and
  960.   BABYTEXT.BIN when they are first created (you can rename them.)  To modify
  961.   the .BIN file, you need only temporarily rename it to a .DAT file (and
  962.   vice-versa.)  Your users will only need to modify the .DAT file.    
  963.  
  964.     To setup your door for use with the TextSystem, you need to change a
  965.   global variable AFTER you call DoorInit() but BEFORE you make any use of
  966.   the TextSystem.  The global variable 'LSTextFile' should be changed to
  967.   hold the path and filename of your .DAT file.  It defaults to LSText.Dat
  968.   (which won't work because it is the LightSpeed data file.)  After you have
  969.   changed this variable, you can use the TextSystem function getText().  Note
  970.   that all strings are 256 bytes.
  971.  
  972.     unsigned char *getText( unsigned int promptNum );
  973.         After you've set the global string 'LSTextFile', this function will
  974.       return string #'promptNum' out of your .DAT file.  
  975.  
  976.   Error Handling:
  977.  
  978.     global char errbuf[ 80 ];
  979.         This is a workspace provided for YOU only.  This can be used by
  980.       sprintf() before making a call to error().
  981.  
  982.     void error( char *err );   // Logs 'err' to disk and displays.  Does not
  983.                                // abort the program, but does delay 2 secnds.
  984.  
  985.   Log File:
  986.  
  987.     global char LSLogFile[ 80 ];
  988.         Before logging anything (but AFTER calling DoorInit()), set this
  989.       global string to the filename for your log file.  For example,
  990.       strcpy( LSLogFile, "MyDoor.Log" );
  991.  
  992.     void add_log( char * )
  993.         After setting 'LSLogFile' call this function to add a new line to
  994.       the logs.  Inside of the string can be some codes:  @USER@ is replaced
  995.       by the user's handle.  @SEC@ is replaced by the user's security class
  996.       (use @SEC@ only with LightSpeed BBS Systems.)  @TIME@ is replaced by
  997.       the current time of day.  @DATE@ is replaced by the current date.
  998.  
  999.   Comma-String Functions:
  1000.  
  1001.     Many places in LightSpeed use a special "comma-based" string.  This
  1002.   string can have multiple items seperated by commas.  Spaces surrounding
  1003.   the commas are truncated.  Any character in the string preceded by a \
  1004.   mark will be accepted as one character (including commas.)  Double slashes
  1005.   become single slashes.  
  1006.  
  1007.     char *get_substring( char *string, int sub, int maxlen=80 );
  1008.         This function will return a pointer to the substring within the
  1009.       main string.  The maximum value for maxlen is 120.  This function will
  1010.       return NULL if there is no sub #'sub'.  The first sub # is 0, the
  1011.       second is 1, so-on. 
  1012.  
  1013.     uchar is_substring( char *string, char *find, int maxlen=80 );
  1014.         This function will return true if 'find' is any of the substrings
  1015.       within 'string'.  This function is not case sensative.
  1016.  
  1017.   General String Functions:
  1018.  
  1019.     void filter( char *string, int maxlen, int style );
  1020.       If 'style' is 0, this removes any characters < 32 (Space) from 'string'.
  1021.       If 'style' is 1, anything other than A-Z, a-z, and space are removed.
  1022.  
  1023.     int wildmatch( char *, char * );  // A strcmpi() with * and ? wildcards.
  1024.  
  1025.     char *get_size( ulong filesize, char *string );
  1026.       Returns a nicely formatted byte display of 'filesize' in 'string'.
  1027.  
  1028.     char *strins( char *string, int at, char whattoinsert=' ' );
  1029.         This function inserts 'whattoinsert' into the string 'string' at
  1030.       'at' spaces from the left.  This will shift everything already present
  1031.       after 'at' to the right.
  1032.  
  1033.     char *strdel( char *string, int at );
  1034.         This function removes the character from the string at position 'at'.
  1035.  
  1036.     char *strstri( char *string, char *find );
  1037.         This function finds 'find' within 'string' in a case INsensative
  1038.       search.  It returns the pointer to where 'find' begins inside of
  1039.       'string' (it points to somewhere in 'string') or NULL if there is no
  1040.       matches found.
  1041.  
  1042.     char *strfind( char *string, char *find );
  1043.         This works just like strstri(), except it also does NOT search inside
  1044.       of quotation (") marks.  It does not treat quotation marks as
  1045.       quotation marks if they are preceded by a \ mark.  Note that a
  1046.       quotation mark cannot be included in 'find'.
  1047.  
  1048.     char *strnfind( char *string, char *find, int maxlen );
  1049.         This works exactly like strnfind(), but only for 'maxlen' characters.
  1050.  
  1051.   Date and Time Functions:
  1052.  
  1053.     int years_since( struct date * );   // Returns years since given date
  1054.  
  1055.     ulong date2int( struct date * );    // Returns days since 1/1/1990
  1056.  
  1057.     void int2date( struct date *, ulong );  // Fills date (from 0/0/0000)
  1058.  
  1059.     void smooth_date( struct date * );
  1060.         This function converts dates with days such as >30 or >31 to a new
  1061.       month, and converts month>12 into new years.  Respects leap-years.
  1062.  
  1063.     void smooth_time( struct time * );      // Makes a valid time
  1064.  
  1065.     char *format_time( struct time *, char *string );    // Fills 'string'
  1066.  
  1067.     void string2date( char *, struct date * );   // Fills date from string
  1068.  
  1069.     uint twodigit( int );     // Returns 19xx as xx (1984 returns 84)
  1070.  
  1071.     uint fourdigit( int, int thisyear );
  1072.         Returns xx or xxxx as xxxx always using 'thisyear'.
  1073.  
  1074.  
  1075.  
  1076.   Miscellanious Data:
  1077.  
  1078.     As soon as DoorInit() is completely, a large number of data items are
  1079.   filled in for you to use as needed.  When operating with a door.sys or in
  1080.   Local mode, only certain data items will be filled.  When operating with
  1081.   InfoLink.Dat files, the entire 'user', 'security', 'node', 'config', and
  1082.   'master' structures are completely filled with the same settings used by
  1083.   the BBS Software.  We won't provide specifics on all the data members, as
  1084.   there are far too many, but you can look at LITE.H for information when
  1085.   using InfoLink.Dat files.  Here are some of the data items of importance:
  1086.  
  1087.    * Most values presented here are given a default value when in local
  1088.   mode.  This default value generally is that of a sysop-user, such as a
  1089.   time limit of 999 minutes.
  1090.  
  1091.     master structure
  1092.       char sysop[20];      // BBS Sysop
  1093.       char ramdrive;       // RamDrive letter (with InfoLink) or HD Letter
  1094.  
  1095.     node structure
  1096.       ID structure
  1097.         unsigned long num;       // Current node number, first node is 0.
  1098.                                  // Defaults to 0 for local mode.
  1099.  
  1100.     user structure
  1101.       ulong num;                 // User number: Valid with dropfiles
  1102.       unsigned char handle[20];  // User's handle: Always valid
  1103.       unsigned char real[20];    // User's real name: Valid with dropfiles
  1104.       unsigned char citystate[20];  // User's 'from': Valid with dropfiles
  1105.       unsigned char vphone[20];  // Voice phone number: Valid with dropfiles
  1106.       unsigned char dphone[20];  // Data phone number: Valid with dropfiles
  1107.       unsigned char password[10];// User's password: Valid with dropfiles
  1108.       struct date expire;        // Security class expires on: Valid w/drop
  1109.       struct date bday;          // User's birthdate: Valid with dropfiles
  1110.       struct date newfiles;      // Last newfile scan: Valid with dropfiles
  1111.       struct date dateon;        // User's last call: Valid with dropfiles
  1112.       struct time timeon;        // Time of last call: Valid with dropfiles
  1113.       int timelimit;             // Time limit: Always valid
  1114.       char proto;                // File transfer protocal:   }
  1115.       long s_uploads;            // Total number of uploads   } Valid with
  1116.       long s_downloads;          // Total number of downloads }    dropfiles
  1117.       long s_upk;                // Total KB uploaded         }
  1118.       long s_downk;              // Total KB downloaded       }
  1119.       long kratio;               // Total KB downloaded (vs uploaded) }
  1120.       long dlratio;              // Total files downloaded (vs uploaded) }
  1121.       char comment[8][40];       // First comment ([0]) is valid }
  1122.       long s_written;            // Total messages written    } Valid w/drop
  1123.  
  1124.     security structure
  1125.       int doorlevel;    // Security level #: Valid with dropfiles (999 local)
  1126.       long klimit;      // Maximum KB allowed for download in a day: Dropfile
  1127.       long dllimit;     // Maximum # of files allowed for d/l a day: Dropfile
  1128.  
  1129.     drop structure
  1130.       int lines;                 // Lines per page: Always valid
  1131.       int terminal;              // Terminal mode: Always valid
  1132.       int redirect;              // RE_LOCAL or RE_ECHO
  1133.  
  1134.   Legend Of the Red Dragon (LORD IGM) support:
  1135.  
  1136.     The shareware LsDoor SDK provides support for creating your own LORD
  1137.   IGMs.  While you may create IGMs with the shareware LsDoor SDK, you may
  1138.   NOT SELL the IGMs until you register.  The registered LsDoor SDK goes a
  1139.   step further and includes the source code for working with LORD in
  1140.   LORD.CPP.  Before registering, LORD.CPP is included in LSDOOR1.LIB and
  1141.   will display a message notifying the user that it uses the shareware
  1142.   LsDoor SDK.  After registering, this message is removed, and instead of
  1143.   being included in the .LIB file, LORD.CPP is provided for you to modify
  1144.   as you wish (You may NOT distribute modifications to the LsDoor SDK in
  1145.   their source code form.)  In the registered LsDoor SDK, make sure to
  1146.   include LORD.CPP in your project.
  1147.     We will not cover all of the LORD support here.  Instead, you can find
  1148.   2 sources for learning to use the LORD kit.  First is a demo IGM called
  1149.   LORDDEMO.CPP (.PRJ, .IDE, etc are included too.)  It demonstrates how to
  1150.   get your IGM installed into LORD, how to uninstall it, how to send mail
  1151.   with LORD, how to check for bad words using LORD's BADWORDS.DAT file, and
  1152.   how to make your IGM run with LORD in the first place.
  1153.     The second source is LORD.H, the header file for the LORD Kit.  This
  1154.   header file is not included in LsDoor.h.  LORD.H is well documented and
  1155.   provides your reference to the LORD Kit.  
  1156.  
  1157.   LightSpeed BBS Specific:
  1158.  
  1159.     These functions only work with LightSpeed BBS systems.  You may need to 
  1160.   be familiar with LightSpeed's operation before working with these.  It is
  1161.   not necessary to use these functions at all, but they may be useful if you
  1162.   are programming specifically for LightSpeed.  You can also check the
  1163.   global flag 'LSPresent', which will be true when LightSpeed is in use
  1164.   and false for any other BBS Software.
  1165.  
  1166.     Note that whenever LightSpeed is in use, the structures 'user',
  1167.   'config', 'node', and 'security' are automatically filled by DoorInit().
  1168.   See the Lite.h header file for the format of these structures.
  1169.  
  1170.     int get_flags( int flagnum );
  1171.         Under LightSpeed, all user accounts have 10 integer flags which be
  1172.       set to OFF, X-Days, or ON.  X-Days sets the flag to expire after so
  1173.       many days have passed.  This function returns true if the flag is ON
  1174.       or has not yet expired, or returns false if OFF or after expiration.
  1175.  
  1176.     int get_submenu( int subnum ); // Is submenu #subnum active (true/false)
  1177.         Under LightSpeed, all security classes have 10 "submenu levels"
  1178.       These submenus specify a time in minutes.  After the user has been
  1179.       online for longer than this time period, the submenu is "off" for that
  1180.       day.
  1181.  
  1182.     int user_security( void );      // Loads 'security' for current user
  1183.  
  1184.     int userserch_security( void ); // Loads 'security' for current userserch
  1185.         The userserch structure is of 'user' type, see Lite.h    
  1186.  
  1187.     int access_mailarea( void );    // Checks if the current security class
  1188.     int access_ularea( void );      // permits access to the current mailarea
  1189.     int access_dlarea( void );      // or filearea.
  1190.     
  1191.     int in_set( uchar *setlist, uint setnum );
  1192.         File and Mail areas in LightSpeed may be divided into sets.  Setlist
  1193.       will point to an array of 5 unsigned characters, if any of the 5
  1194.       uchar's match setnum, this function returns true.
  1195.  
  1196.     void sysop_userDB( int start );  // Opens sysop database on user #'start'
  1197.     void sysop_fileDB( int newuploads );
  1198.         This function opens the file database.  If newuploads is set to 1,
  1199.       only files marked as 'new uploads' will be displayed.  Otherwise,
  1200.       all files will be shown.
  1201.  
  1202.   Advanced Programmer's Tricks:
  1203.  
  1204.     You might have the occasion to turn off the cursor.  Normally that isn't
  1205.   too hard, but if you want to do it and have it work in DesqView, Windows
  1206.   95, and DOS all at once it takes a little more.  Note that there is no
  1207.   technique to turn off a remote user's cursor using ANSI, so this only
  1208.   affects the sysop's perspective.
  1209.     Set AH = 0x0F, generate interrupt 0x10.  This gives you the current
  1210.   video mode in AL.  Now, set AH = 0x01, CX = 0x2002, and generate
  1211.   interrupt 0x10.  This procedure covers some bugs in AMI 386 BIOS and AST
  1212.   Premier 386 BIOS which require the current video mode in AL or a system
  1213.   crash results.  This procedure may not work properly on EGA systems.
  1214.  
  1215.   Technical Support:
  1216.  
  1217.     We will attempt to offer technical support to everyone, even those who
  1218.   haven't registered the program.  However we have very limited resources for
  1219.   technical support, so everyone can expect to have a little work getting a
  1220.   hold of us.
  1221.     All the company's technical support is handled by myself, Wiley Black.
  1222.   I am the lead programmer on the LightSpeed team, and the author of most of
  1223.   this document.  My name is pronounced "Why-Lee" just like in "Wile E.
  1224.   Coyote".
  1225.     I can be reached by modem on the Terror's Zone BBS at (505) 865-0116 or 
  1226.   (505) 865-7789 anytime.  Login using the account "Guest" and the password 
  1227.   "LS" for quickest access to our BBS.  I am the system operator, "Terror".
  1228.   Terror's Zone BBS runs using LightSpeed as well as a number of LsDoor 
  1229.   programs.
  1230.     I can also be reached by voice at (505) 866-5193.  This is my home phone
  1231.   number, and if you want voice support, you can expect me to be out a lot.
  1232.   PLEASE don't call this number except between these hours:
  1233.  
  1234.     Between June and August:     * All times are Mountain Standard (MST) *
  1235.       From noon to 8 PM
  1236.     The rest of the year:
  1237.       Weekdays from 4 PM to 8 PM
  1238.       Saturday and Sunday from noon to 8 PM
  1239.  
  1240.     These numbers may not be valid after January of 1997.  You should acquire
  1241.   a more recent copy of the LsDoor SDK before calling.
  1242.  
  1243.     *REGISTERED USERS TECHNICAL SUPPORT*
  1244.  
  1245.     If you are a registered user, the easiest way to get voice support is to 
  1246.   leave me a message with your name, phone number, and the times (MST) for me
  1247.   to call.  You can leave a message on Terror's Zone BBS, or on my answering
  1248.   machine.  I'm sorry but I can't afford to pay long-distance charges for
  1249.   anyone who hasn't registered.
  1250.  
  1251.